#include "OldMatch.h"
#include "TeamManager.h"
#include "RandomSystem.h"
#include "GameSettings.h"
#include "ServiceProvider.h"
#include "People.h"
#include "StringUtilities.h"
#include "Team.h"

#include <cassert>

OldMatch::OldMatch(ServiceProvider* i_sp)
	:MatchInterface(i_sp)
{
}

void OldMatch::InnerInit(void* /*i_innerParams*/)
{
	m_matchDuration = m_sp->GetSettings().GetValue("I_MATCH_DURATION");
	m_numberOfTitolars = Team::GetParams().TITOLARS_PLAYERS;

	// starting evaluation is 6. (look at the forumulas...)
	static const int MATCH_STARTING_PLUS = 10;
	static const int MATCH_STARTING_MINUS = 10;

	if(m_matchData.IsPlayingTeam(Utilities::INVALID_ID))
		return;

	for (int j = 0; j < 2; ++j)
	{
		const Team* const team = m_sp->GetTeamMgr().GetTeam(m_matchData.m_teamData[j].m_teamID);
		const PeopleVec& playerList = team->GetPlayersList();
		OldMatchTeamData& data = m_data[j];

		data.m_team = team;

		data.m_conditions.resize(m_numberOfTitolars);

		data.m_gkBaseSkill = playerList.at(0)->GetSkills().m_playerSkills[Goalkeeper];

		data.m_BaseAttackSkills.resize(m_numberOfTitolars);
		data.m_BaseRoleAttackFactor.resize(m_numberOfTitolars);
		data.m_AttackSkills.resize(m_numberOfTitolars);
		data.m_RoleAttackFactor.resize(m_numberOfTitolars);
		data.m_InvRoleAttackFactor.resize(m_numberOfTitolars);

		data.m_BaseDefenseSkills.resize(m_numberOfTitolars);
		data.m_BaseRoleDefenseFactor.resize(m_numberOfTitolars);
		data.m_DefenseSkills.resize(m_numberOfTitolars);
		data.m_RoleDefenseFactor.resize(m_numberOfTitolars);
		data.m_InvRoleDefenseFactor.resize(m_numberOfTitolars);

		data.m_roles.resize(m_numberOfTitolars);

		data.m_Aggressivity.resize(m_numberOfTitolars);
		data.m_Plus.resize(m_numberOfTitolars);
		data.m_Minus.resize(m_numberOfTitolars);

		data.m_shoots.resize(m_numberOfTitolars);
		data.m_atk_total.resize(m_numberOfTitolars);
		data.m_atk_won.resize(m_numberOfTitolars);
		data.m_def_total.resize(m_numberOfTitolars);
		data.m_def_won.resize(m_numberOfTitolars);
		data.m_fouls.resize(m_numberOfTitolars);

		data.m_team_shoots = 0;
		data.m_team_atk_total = 0;
		data.m_team_atk_won = 0;
		data.m_team_def_total = 0;
		data.m_team_def_won = 0;
		data.m_team_fouls = 0;

		const int formation = team->GetFormation();
		data.m_formation = formation;

		for (unsigned int i = 0; i<m_numberOfTitolars; ++i)
		{
			const People& thePlayer = *playerList.at(i);
			const PeopleSkills& skill = thePlayer.GetSkills();

			const int atk = skill.m_playerSkills[Attacker];
			const int def = skill.m_playerSkills[Defender];
			data.m_BaseAttackSkills[i]	= atk;
			data.m_BaseDefenseSkills[i]	= def;

			const int role = team->GetRoleByIndex(i);
			data.m_roles[i] = role;
			const int atkPerc = Team::ROLE_ROLE_PERCENT_PLAYING[formation][role][Attacker];
			const int defPerc = Team::ROLE_ROLE_PERCENT_PLAYING[formation][role][Defender];

			data.m_BaseRoleAttackFactor[i]	= atk * atkPerc / 100;
			data.m_BaseRoleDefenseFactor[i]	= def * defPerc / 100;

			data.m_Aggressivity[i] = (i!=0 ? skill.m_mentalSkills[Aggressivity] : skill.m_mentalSkills[Aggressivity]/5);
			data.m_Plus[i] = MATCH_STARTING_PLUS;
			data.m_Minus[i] = MATCH_STARTING_MINUS;
			
			data.m_conditions[i] = -1; //so CalcActualSkillsUnsafe will detect a "change"

			CalcActualSkillsUnsafe(j, i);

			data.m_shoots[i] = 0;
			data.m_atk_total[i] = 0;
			data.m_atk_won[i] = 0;
			data.m_def_total[i] = 0;
			data.m_def_won[i] = 0;
			data.m_fouls[i] = 0;
		}
		RecalcSums(j);
	}
}

void OldMatch::CalcActualSkills(const int i_team, const int i_player)
{
	if(CalcActualSkillsUnsafe(i_team, i_player))
	{
		RecalcSums(i_team);
	}
}

int OldMatch::GetConditionPercent(const int i_team, const int i_player) const
{
	const OldMatchTeamData& data = m_data[i_team];
	const MatchPlayerData& pd = m_matchData.m_teamData[i_team].m_playerData[i_player];

	if(IsRedCard(pd.m_cards))
		return 50;
	
	if (pd.m_stamina <= 0)
		return 60;
	
	if (pd.m_stamina <= data.m_team->GetPlayersList().at(i_player)->GetSkills().m_physicsSkills[Resistance]/2)
		return 80;

	return 100;
}

bool OldMatch::CalcActualSkillsUnsafe(const int i_team, const int i_player)
{
	OldMatchTeamData& data = m_data[i_team];

	const int percent = GetConditionPercent(i_team, i_player);

	if(percent != data.m_conditions[i_player])
	{
		data.m_conditions[i_player] = percent;

		data.m_AttackSkills[i_player] = STL::max(1, data.m_BaseAttackSkills[i_player] * percent / 100);
		data.m_DefenseSkills[i_player] = STL::max(1, data.m_BaseDefenseSkills[i_player] * percent / 100);
		data.m_RoleAttackFactor[i_player] = STL::max(1, data.m_BaseRoleAttackFactor[i_player] * percent / 100);
		data.m_RoleDefenseFactor[i_player] = STL::max(1, data.m_BaseRoleDefenseFactor[i_player] * percent / 100);
		
		int temp;
		temp = 100 * Team::ROLE_ROLE_PERCENT_PLAYING[data.m_formation][data.m_roles[i_player]][Attacker] / data.m_AttackSkills[i_player];
		data.m_InvRoleAttackFactor[i_player] = STL::max(1, temp);

		temp = 100 * Team::ROLE_ROLE_PERCENT_PLAYING[data.m_formation][data.m_roles[i_player]][Defender] / data.m_DefenseSkills[i_player];
		data.m_InvRoleDefenseFactor[i_player] = STL::max(1, temp);

		if(i_player == 0)
			data.m_gkSkill = STL::max(1, data.m_gkBaseSkill * percent / 100);

		return true;
	}

	return false;
}

void OldMatch::RecalcSums(const int i_team)
{
	OldMatchTeamData& data = m_data[i_team];

	data.m_RoleAttackFactorSum = 0;
	data.m_RoleDefenseFactorSum = 0;
	data.m_RoleDefenseSelectorSum = 0;
	data.m_InvRoleAttackFactorSum = 0;
	data.m_InvRoleDefenseFactorSum = 0;
	data.m_AggSum = 0;

	for (unsigned int i = 0; i< m_numberOfTitolars; ++i)
	{
		data.m_RoleAttackFactorSum += data.m_RoleAttackFactor[i];
		data.m_InvRoleAttackFactorSum += data.m_InvRoleAttackFactor[i];
		data.m_RoleDefenseFactorSum += data.m_RoleDefenseFactor[i];
		data.m_InvRoleDefenseFactorSum += data.m_InvRoleDefenseFactor[i];
		data.m_AggSum += data.m_Aggressivity[i];
	}
	data.m_RoleDefenseSelectorSum = data.m_RoleDefenseFactorSum - data.m_RoleDefenseFactor[0];
}

const STL::string& OldMatch::CurrentResult(STL::string& o_str) const
{
	o_str = Utilities::IntToString(m_matchData.m_teamData[0].m_goals);
	o_str += " - ";
	o_str += Utilities::IntToString(m_matchData.m_teamData[1].m_goals);
	return o_str;
}

const STL::string& OldMatch::GetPlayerDecoratedName(const int i_team, const int i_player, STL::string& o_str) const
{
	o_str = m_data[i_team].m_team->GetPlayersList()[i_player]->GetName();
	o_str += " (";
	o_str += HomeAwayString(i_team);
	o_str += ")";
	return o_str;
}

void OldMatch::UpdateStaminas(const int i_minute, const bool i_produceEvents)
{
	static const size_t numberOfGoalkeepers = 1;
	static const size_t numberOfDefenders = 2;
	static const int StaminaFactor[NUM_TEAM_FORMATIONS][NUM_FORMATION_ROLES] = 
	{
		{15,20, 0,25}, //TEAM_FORMATION_202
		{15,15,30,20}, //TEAM_FORMATION_121
		{15, 0,30, 0}  //TEAM_FORMATION_040
	};
	
	for(int j=0; j<2; ++j)
	{
		MatchTeamData& data = m_matchData.m_teamData[j];
		const int formation = m_data[j].m_formation;

		for(size_t i=0; i<data.m_playerData.size(); ++i)
		{
			const int maxRand = StaminaFactor[formation][m_data[j].m_roles[i]];
			const int staminaInc = -(Rand()%maxRand)/10;
			if(staminaInc!=0)
				UpdateStamina(j, i, i_minute, i_produceEvents, staminaInc);
		}
	}
}

//// optimized after profiling : hardcoded 5 players per team
//void OldMatch::UpdateStaminas(const int i_minute, const bool i_produceEvents)
//{
//	static const int StaminaFactor[] = {15,20,20,25,25};
//	
//	for(int j=0; j<10; ++j)
//	{
//		const int staminaInc = (Rand()%StaminaFactor[j/2])/(-10);
//		if(staminaInc!=0)
//			UpdateStamina(j%2, j/2, i_minute, i_produceEvents, staminaInc);
//	}
//}
//

void OldMatch::UpdateStamina(const int i_team, const int i_player, const int i_minute, const bool i_produceEvents, const int i_toBeAdded)
{
	MatchPlayerData& data = m_matchData.m_teamData[i_team].m_playerData[i_player];
	if (i_produceEvents)
	{
		const int nextStamina = data.m_stamina + i_toBeAdded;
		const int threshold = m_data[i_team].m_team->GetPlayersList().at(i_player)->GetSkills().m_physicsSkills[Resistance]/2;

		if ( (i_toBeAdded < 0) && (data.m_stamina > threshold) && (nextStamina <= threshold) )
			AppendEvent(i_minute, "semitired", GetPlayerDecoratedName(i_team, i_player, m_tempString));

		if ( (i_toBeAdded < 0) && (data.m_stamina > 0) && (nextStamina <= 0) )
			AppendEvent(i_minute, "tired", GetPlayerDecoratedName(i_team, i_player, m_tempString));

		if ( (i_toBeAdded > 0) && (data.m_stamina <= 0) && (nextStamina > 0) )
			AppendEvent(i_minute, "restored", GetPlayerDecoratedName(i_team, i_player, m_tempString));

		if ( (i_toBeAdded > 0) && (data.m_stamina <= threshold) && (nextStamina > threshold) )
			AppendEvent(i_minute, "semirestored", GetPlayerDecoratedName(i_team, i_player, m_tempString));
	}

	data.m_stamina += i_toBeAdded;
	if(i_minute % 2 == 0)
		CalcActualSkills(i_team, i_player);
}

void OldMatch::CheckInMatchInjury()
{
	//TODO: a player can be injuried during the match
}

void OldMatch::PostMatchPlayerUpdate(const bool i_produceEvents)
{
	// Evaluations, Skills Update, Fatugue Update, Injury Check, Healing of non playing players..
	for(int j=0; j<2; ++j)
	{
		const Team* team = m_data[j].m_team;
		const PeopleVec& trainers = team->GetTrainersList();
		People* const * const trainersRoles = team->GetTrainersRoleList();
		const PeopleVec& playerList = team->GetPlayersList();

		for(int i=0; i<static_cast<int>(playerList.size()); ++i)
		{
			People& player = *playerList[i];
			const bool isTired = ((i < static_cast<int>(Team::GetParams().TITOLARS_PLAYERS)) ? (m_matchData.m_teamData[j].m_playerData[i].m_stamina <= 0) : false);
			int daysPenalty, daysInjury;

			const MatchPlayerData& data = m_matchData.m_teamData[j].m_playerData[i%m_numberOfTitolars];
			const int role = ((i < m_numberOfTitolars) ? m_data[j].m_roles[i] : NUM_FORMATION_ROLES);

			player.PlayerPostMatch(
				role,
				m_data[j].m_formation,
				(i<m_numberOfTitolars ? data.m_goals : 0), 
				(i<m_numberOfTitolars ? data.m_evaluation : 0),
				(i == m_matchData.m_playerMOM && j == m_matchData.m_teamMOM),
				(i<m_numberOfTitolars ? data.m_cards : 0),
				isTired, trainersRoles, &daysPenalty, &daysInjury);

			if(i_produceEvents)
			{
				if(daysPenalty != 0)
					AppendEvent(m_matchDuration, "penalty", GetPlayerDecoratedName(j, i, m_tempString));
				if(daysInjury != 0)
					AppendEvent(m_matchDuration, "injuries", GetPlayerDecoratedName(j, i, m_tempString));
			}
		}

		for(size_t i=0; i<trainers.size(); ++i)
			trainers[i]->TrainerPostMatch(team->GetTrainedRoles(trainers[i]));
	}
}

void OldMatch::CheckPenalty(const int i_minute, const size_t i_team, const bool i_produceEvents)
{
	const int SEVERITY_REFEREE = 1200;

	MatchTeamData& teamData = m_matchData.m_teamData[i_team];
	OldMatchTeamData& data = m_data[i_team];

	//TODO: dangerous, possibly infinite loop...
	const int aggressivePlayerIndex = RandSelect(data.m_Aggressivity, data.m_AggSum);

	MatchPlayerData& theAggressivePlayer = teamData.m_playerData[aggressivePlayerIndex];

	const bool isPenalty = ((Rand()%10) == aggressivePlayerIndex);
	if(i_produceEvents && isPenalty)
		AppendEvent(i_minute, "penaltykickfoul", GetPlayerDecoratedName(i_team, aggressivePlayerIndex, m_tempString));

	const int diceRollAmmo = RandIntBetween(1, SEVERITY_REFEREE);
	if (diceRollAmmo <= (data.m_AggSum))
	{
		const bool redFoul = (diceRollAmmo <= (data.m_AggSum)/10);
		if(redFoul)
		{
			if(IsNoneCard(theAggressivePlayer.m_cards))
			{
				if(i_produceEvents)
					AppendEvent(i_minute, "firstRed", GetPlayerDecoratedName(i_team, aggressivePlayerIndex, m_tempString));
				theAggressivePlayer.m_cards = CardRed;

			}
			else if(IsYellowCard(theAggressivePlayer.m_cards))
			{
				if(i_produceEvents)
					AppendEvent(i_minute, "yellowRed", GetPlayerDecoratedName(i_team, aggressivePlayerIndex, m_tempString));
				theAggressivePlayer.m_cards = CardYellowRed;
			}
			else
			{
				if(i_produceEvents)
					AppendEvent(i_minute, "secondRed", GetPlayerDecoratedName(i_team, aggressivePlayerIndex, m_tempString));
				theAggressivePlayer.m_cards += 2;
			}
		}
		else
		{
			if(IsNoneCard(theAggressivePlayer.m_cards))
			{
				if(i_produceEvents)
					AppendEvent(i_minute, "firstYellow", GetPlayerDecoratedName(i_team, aggressivePlayerIndex, m_tempString));
				theAggressivePlayer.m_cards = CardYellow;
			}
			else if(IsYellowCard(theAggressivePlayer.m_cards))
			{
				const int diceRollExp = RandIntBetween(1,100);
				const int SEVERETY_REFEREE_RED_CARD = 65;

				if (diceRollExp <= SEVERETY_REFEREE_RED_CARD)
				{
					if(i_produceEvents)
						AppendEvent(i_minute, "secondYellow",GetPlayerDecoratedName(i_team, aggressivePlayerIndex, m_tempString));
					theAggressivePlayer.m_cards = CardYellowYellow;
				}
				else
				{
					if(i_produceEvents)
						AppendEvent(i_minute, "secondYellowSaved", GetPlayerDecoratedName(i_team, aggressivePlayerIndex, m_tempString));
				}
			}
			else
			{
				if(i_produceEvents)
					AppendEvent(i_minute, "secondRed", GetPlayerDecoratedName(i_team, aggressivePlayerIndex, m_tempString));

				if(theAggressivePlayer.m_cards < CardYellowRed)
					theAggressivePlayer.m_cards = CardYellowRed;
				else
					++theAggressivePlayer.m_cards;
			}
		}
	}
	else
	{
		if(i_produceEvents)
			AppendEvent(i_minute, "warning", GetPlayerDecoratedName(i_team, aggressivePlayerIndex, m_tempString));
	}

	++data.m_team_fouls;
	++data.m_fouls[aggressivePlayerIndex];
	if(i_produceEvents && (data.m_team_fouls==5))
		AppendEvent(i_minute, "fifthfoul");
	if(isPenalty)
		PenaltyKick(i_minute, 1-i_team, i_produceEvents);
	else if(data.m_team_fouls > 5)
		FreeKick(i_minute, 1-i_team, i_produceEvents);
}

void OldMatch::CheckForfait(int& io_minute)
{
	//TODO: fix this condition... we've already recorded in history the goals done by scoring players...
	for(int j = 0; j < 2; ++j)
	{
		if(IsRedCard(m_matchData.m_teamData[j].m_playerData[0].m_cards))
		{
			AppendEvent(io_minute, "forfait", m_data[1-j].m_team->GetName());
			m_matchData.m_teamData[j].m_goals = 0;
			m_matchData.m_teamData[1-j].m_goals = 3;
			io_minute = m_sp->GetSettings().GetValue("I_MATCH_DURATION");
		}
	}
}

void OldMatch::CalcEvaluations()
{
	m_matchData.m_teamMOM = 0;
	m_matchData.m_playerMOM = 0;
	int maxEval = 0;
	for(size_t j = 0; j < 2; ++j)
	{
		for(size_t i=0; i<Team::GetParams().TITOLARS_PLAYERS; ++i)
		{
			const int den = m_data[j].m_Plus[i] + m_data[j].m_Minus[i];
			const int num = m_data[j].m_Plus[i] * 1600;
			const int denorm = num/den - 200;
			m_matchData.m_teamData[j].m_playerData[i].m_evaluation = STL::max(100, STL::min(1000,denorm));

			if(denorm > maxEval)
			{
				m_matchData.m_teamMOM = j;
				m_matchData.m_playerMOM = i;
				maxEval = denorm;
			}
		}
	}			
}

void OldMatch::UpdateEval(const int i_team, const int i_player, const int i_howMuch, const bool i_plus)
{
	(i_plus ? m_data[i_team].m_Plus : m_data[i_team].m_Minus)[i_player] += i_howMuch;
}

void OldMatch::EvaluationsEvents(const int i_minute)
{
	using namespace Utilities;
	static const char* s_cards[] = {"      ", " [Y]  ", " [YY] ", " [R]  ", " [YR] ", " [RR] "};
	STL::string name;
	STL::string message;

	static STL::string s_pagelle("<->");
	AppendRawEvent(i_minute, s_pagelle);
	AppendRawEvent(i_minute, "Pagelle");
	for(int j=0; j<2; ++j)
	{
		message = STL::string("Team: ") + m_data[j].m_team->GetName();
		AppendRawEvent(i_minute, message);
		message.clear();
		message.resize(People::GetParams().MAX_CHAR_NAME + 1, ' ');
		message += "           GOAL SHOT ATK  ATKT DEF  DEFT FOULS";
		AppendRawEvent(i_minute, message);
		for(int i=0; i<static_cast<int>(Team::GetParams().TITOLARS_PLAYERS); ++i)
		{
			message = " ";
			message += EvalToStr(m_matchData.m_teamData[j].m_playerData[i].m_evaluation);
			message += s_cards[STL::min(5, m_matchData.m_teamData[j].m_playerData[i].m_cards)];
			name = m_data[j].m_team->GetPlayersList().at(i)->GetName();
			name.resize(People::GetParams().MAX_CHAR_NAME + 1, ' ');
			message += name.c_str();

			message += TabUpTo(m_matchData.m_teamData[j].m_playerData[i].m_goals, 5);
			message += TabUpTo(m_data[j].m_shoots[i], 5);
			message += TabUpTo(m_data[j].m_atk_won[i], 5);
			message += TabUpTo(m_data[j].m_atk_total[i], 5);
			message += TabUpTo(m_data[j].m_def_won[i], 5);
			message += TabUpTo(m_data[j].m_def_total[i], 5);
			message += TabUpTo(m_data[j].m_fouls[i], 5);

			if(j == m_matchData.m_teamMOM && i == m_matchData.m_playerMOM)
				message += "   ***MOM***";

			AppendRawEvent(i_minute, message);
		}
		message.clear();
		message.resize(People::GetParams().MAX_CHAR_NAME + 1, ' ');
		message += "           ";

		message += TabUpTo(m_matchData.m_teamData[j].m_goals, 5);
		message += TabUpTo(m_data[j].m_team_shoots, 5);
		message += TabUpTo(m_data[j].m_team_atk_won, 5);
		message += TabUpTo(m_data[j].m_team_atk_total, 5);
		message += TabUpTo(m_data[j].m_team_def_won, 5);
		message += TabUpTo(m_data[j].m_team_def_total, 5);
		message += TabUpTo(m_data[j].m_team_fouls, 5);

		AppendRawEvent(i_minute, message);
	}
	AppendRawEvent(i_minute, s_pagelle);
}

void OldMatch::PostMatchEvents()
{
	AppendRawEvent(m_matchDuration, "");
	AppendEvent(m_matchDuration, "postmatch", CurrentResult(m_tempString));
	EvaluationsEvents(m_matchDuration);
}

void OldMatch::PreMatchEvents()
{
	AppendEvent(0, "weather");
	AppendEvent(0, "location");
	TeamsCondition(0);
	TeamsCondition(1);
}

void OldMatch::HalfTimeEvents()
{
	const int halfTime = m_matchDuration/2;
	AppendRawEvent(halfTime, "");
	AppendEvent(halfTime, "break", CurrentResult(m_tempString));
	EvaluationsEvents(halfTime);
}

void OldMatch::ExtraTimeEvents(const int i_minute, const int i_extraTime)
{
	if(i_extraTime == 0)
		AppendEvent(i_minute, "noextratime");
	else
		AppendEvent(i_minute, "extratime", Utilities::IntToString(i_extraTime));
}

const STL::string& OldMatch::HomeAwayString(const int i_team) const
{
	static STL::string s_haStrings[2] = {"H", "A"};
	return s_haStrings[i_team];
}

void OldMatch::TeamsCondition(size_t i_team)
{
	const PeopleVec& playerList = m_data[i_team].m_team->GetPlayersList();
	for (int i=0; i< m_numberOfTitolars; ++i)
	{
		const People& thePlayer = *playerList[i];
		if (thePlayer.GetAvailability().IsBroken())
			AppendEvent(0, "injuried", GetPlayerDecoratedName(i_team, i, m_tempString));
		else if (GetConditionPercent(i_team, i) == 80)
			AppendEvent(0, "semitired", GetPlayerDecoratedName(i_team, i, m_tempString));
		else if (GetConditionPercent(i_team, i) == 60)
			AppendEvent(0, "tired", GetPlayerDecoratedName(i_team, i, m_tempString));
	}
}

void OldMatch::HalfTime(const bool i_produceEvents)
{
	CalcEvaluations();
	if(i_produceEvents)
		HalfTimeEvents();
}

void OldMatch::CalcWinEval()
{
	if(m_matchData.m_teamData[0].m_goals != m_matchData.m_teamData[1].m_goals)
	{
		const int winTeam = (m_matchData.m_teamData[0].m_goals > m_matchData.m_teamData[1].m_goals ? 0 : 1);
		for (int i=0; i<m_numberOfTitolars; ++i)
		{
			const int* const wskill = m_data[winTeam].m_team->GetPlayersList().at(i)->GetSkills().m_playerSkills.m_skills;
			UpdateEval(winTeam, i, 1 + RandSelect(50, wskill[Goalkeeper]) + RandSelect(50, wskill[Defender]) + RandSelect(50, wskill[Attacker]), true);
			const int* const lskill = m_data[1-winTeam].m_team->GetPlayersList().at(i)->GetSkills().m_playerSkills.m_skills;
			UpdateEval(1-winTeam, i, 1 + RandSelect(lskill[Goalkeeper], 50) + RandSelect(lskill[Defender], 50) + RandSelect(lskill[Attacker], 50), false);
		}
	}
}

void OldMatch::PlayMatch(const bool i_produceEvents)
{
	//Condizioni pre-partita:
	if(i_produceEvents)
		PreMatchEvents();

	PlayHalfMatch(1, i_produceEvents);
	HalfTime(i_produceEvents);
	PlayHalfMatch(m_matchDuration/2 + 1, i_produceEvents);

	CalcWinEval();
	CalcEvaluations();

	PostMatchPlayerUpdate(i_produceEvents);

	if(i_produceEvents)
		PostMatchEvents();
}

int	CalculateExtraTime(const int i_factor)
{
	int factor = i_factor;
	int retVal = 0;
	int randNum = Rand()%100;
	while(randNum < factor)
	{
		++retVal;
		factor/=2;
		randNum = Rand()%100;
	}

	return retVal;
}

void OldMatch::PlayHalfMatch(const int i_startingMinute, const bool i_produceEvents)
{
	static const int EXTRA_TIME_ACTION_FACTORS[NUM_ACTION_EVENTS] = {0,1,1,2};
	int extraTimeBudget = 0;
	int numExtraTimeEvents = 0;

	const int halfDuration = m_matchDuration/2;
	const int noExtraTimeLastMinute = i_startingMinute + halfDuration - 1;

	int minute = i_startingMinute;
	int endMinute = noExtraTimeLastMinute + 1;
	
	while (minute < endMinute) 
	{
		bool noEvents = true;

		// actions
		int actionResult = CheckActions(minute, i_produceEvents);
		numExtraTimeEvents += actionResult;
		if(actionResult != NONE)
		{
			extraTimeBudget += numExtraTimeEvents;
			noEvents = false;
		}

		// aggressivity, discipline
		const int aggFactorH = m_data[0].m_AggSum;
		const int aggFactorA = m_data[1].m_AggSum;
		const int aggProbability = aggFactorH + aggFactorA;
		const int diceRollFoul = Rand()%3000;
		if(diceRollFoul <= aggProbability)
		{
			CheckPenalty(minute, RandSelect(aggFactorH, aggFactorA), i_produceEvents);
			extraTimeBudget += ++numExtraTimeEvents;
			//CheckForfait(minute);
			noEvents = false;
		}

		// stamina, injury
		UpdateStaminas(minute, i_produceEvents);
		CheckInMatchInjury(); //todo: if injury, noEvent = false

		if(i_produceEvents && noEvents)
			AppendRawEvent(minute, "...");

		// extra time
		if(minute == noExtraTimeLastMinute)
		{
			const int extraTime = CalculateExtraTime(extraTimeBudget);
			endMinute += extraTime;
			if(i_produceEvents)
				ExtraTimeEvents(minute, extraTime);
		}

		++minute;
	}
}

